package tianrun.ziguan.api.calculate.config.service.sync.handler.template;

import com.baomidou.mybatisplus.core.toolkit.StringPool;
import com.google.common.collect.Lists;
import com.google.common.collect.Maps;
import org.springframework.beans.BeanUtils;
import org.springframework.stereotype.Service;
import tianrun.ziguan.api.calculate.config.dto.request.EdgeInputInstanceVO;
import tianrun.ziguan.api.calculate.config.dto.request.IndicatorsInstanceVO;
import tianrun.ziguan.api.calculate.config.dto.request.StaticPropertiesInstanceVO;
import tianrun.ziguan.api.calculate.config.entity.*;
import tianrun.ziguan.api.calculate.config.enums.MoldEnum;
import tianrun.ziguan.api.calculate.config.service.sync.SyncType;
import tianrun.ziguan.api.calculate.config.service.sync.handler.AbstractSyncHandler;
import tianrun.ziguan.api.calculate.config.service.sync.handler.SyncHandler;
import tianrun.ziguan.api.calculate.config.service.template.ITTemplateService;
import tianrun.ziguan.api.calculate.config.service.template.instance.ITStaticPropertiesInstanceService;
import tianrun.ziguan.api.calculate.config.service.template.module.ITStaticPropertiesModuleService;
import tianrun.ziguan.api.calculate.config.utils.MyBeanUtil;
import tianrun.ziguan.api.calculate.config.utils.Setter;
import tianrun.ziguan.api.common.util.ListUtil;

import java.util.*;
import java.util.function.Function;
import java.util.stream.Collectors;

@Service
public class StaticPropertiesModuleHandler extends AbstractSyncHandler {

    private final ITStaticPropertiesModuleService staticPropertiesModuleService;
    private final ITStaticPropertiesInstanceService staticPropertiesInstanceService;
    private final ITTemplateService templateService;

    public StaticPropertiesModuleHandler(ITStaticPropertiesModuleService staticPropertiesModuleService, ITStaticPropertiesInstanceService staticPropertiesInstanceService, ITTemplateService templateService) {
        this.staticPropertiesModuleService = staticPropertiesModuleService;
        this.staticPropertiesInstanceService = staticPropertiesInstanceService;
        this.templateService = templateService;
    }

    @Override
    public MoldEnum mold() {
        return MoldEnum.StaticProperty;
    }

    @Override
    public SyncType type() {
        return SyncType.TEMPLATE;
    }

    @Override
    public void handler(Set<Long> moduleIds, Set<Long> parentIds) {
        Map<TStaticPropertiesModule, List<TStaticPropertiesInstance>> map = new HashMap<>();
        List<TTemplate> templates = templateService.getByIds(parentIds);
        //1获取模板下的所有组件和实例
        List<TStaticPropertiesModule> sourceModules = staticPropertiesModuleService.getByIds(moduleIds);
        List<TStaticPropertiesInstance> sourceInstances = staticPropertiesInstanceService.listByModuleIds(moduleIds);

        Map<TStaticPropertiesModule, List<TStaticPropertiesInstance>> sourceMap = sourceModules.stream().collect(Collectors.toMap(Function.identity(), module -> sourceInstances.stream().filter(i -> Objects.equals(i.getModuleId(), module.getId())).collect(Collectors.toList())));

        //2获取对应的模板下的组件和实例
        List<TStaticPropertiesModule> staticPropertiesModules = staticPropertiesModuleService.getByTemplate(parentIds);
        List<StaticPropertiesInstanceVO> staticPropertiesInstanceVOS = staticPropertiesInstanceService.listVOByTemplateIds(parentIds);
        Map<Long, List<StaticPropertiesInstanceVO>> templateIdInstancesMap = ListUtil.groupList(staticPropertiesInstanceVOS, StaticPropertiesInstanceVO::getTemplateId);

        Map<Long, List<TStaticPropertiesModule>> targetMap = new HashMap<>();
        //初始化
        templates.forEach(template -> targetMap.put(template.getId(), Lists.newArrayList()));
        targetMap.putAll(ListUtil.groupList(staticPropertiesModules, TStaticPropertiesModule::getTemplateId));


        //对比-组件和实例的关联字段
        targetMap.forEach((templateId, targetModules) -> {
            sourceMap.forEach((sourceModule, sourceInstanceList) -> {
                Optional<TStaticPropertiesModule> first = targetModules.stream().filter(m -> Objects.equals(m.getName(), sourceModule.getName())).findFirst();
                TStaticPropertiesModule newTargetModule = first.orElseGet(TStaticPropertiesModule::new);
                MyBeanUtil.doCopy(sourceModule, newTargetModule,
                        Setter.set(newTargetModule::setId, newTargetModule.getId()),
                        Setter.set(newTargetModule::setTemplateId, templateId));
                List<TStaticPropertiesInstance> collect = templateIdInstancesMap.getOrDefault(templateId, Lists.newArrayList()).stream().map(v -> (TStaticPropertiesInstance) v).collect(Collectors.toList());
                map.put(newTargetModule, getNewTargetTemplateInstances(collect, sourceInstanceList, newTargetModule, TStaticPropertiesInstance.class));
            });
        });
        //修改数据
        if (map.isEmpty()) return;
        staticPropertiesModuleService.saveOrUpdateBatch(map.keySet());
        map.forEach((module, instances) -> instances.forEach(instance -> instance.setModuleId(module.getId())));
        List<TStaticPropertiesInstance> saveInstances = map.values().stream().flatMap(Collection::stream).collect(Collectors.toList());
        if (saveInstances.isEmpty())return;
        staticPropertiesInstanceService.saveOrUpdateBatch(saveInstances);
        // TODO: 2023/11/4 是否删除组件内的其它实例? 删除解除下面注释就行
        //删除组件内其它的实例
        /*List<Long> instanceIds = saveInstances.stream().map(TStaticPropertiesInstance::getId).collect(Collectors.toList());
        staticPropertiesInstanceService.remove(Wrappers.
                <TStaticPropertiesInstance>lambdaQuery().
                in(TStaticPropertiesInstance::getModuleId, map.keySet().stream().map(TStaticPropertiesModule::getId).collect(Collectors.toList())).
                notIn(TStaticPropertiesInstance::getId, instanceIds));*/
    }

    //@Override
    public void handler1(Set<Long> moduleIds, Set<Long> parentIds) {
        // 预先生成module
        Map<Long, Map<Long, TStaticPropertiesModule>> modules = getModules(moduleIds, parentIds);
        Collection<TStaticPropertiesInstance> sources = staticPropertiesInstanceService.listByModuleIds(moduleIds);
        Collection<StaticPropertiesInstanceVO> targets = staticPropertiesInstanceService.listVOByTemplateIds(parentIds);
        // 按模板对实例进行分组
        Map<Long, List<StaticPropertiesInstanceVO>> templateMapping = targets.stream().collect(Collectors.groupingBy(StaticPropertiesInstanceVO::getTemplateId));

        List<TStaticPropertiesInstance> list = Lists.newArrayList();
        List<Long> delIds = Lists.newArrayList();
        // 遍历所有模板下的实例
        for (TStaticPropertiesInstance source : sources) {
            // 获取实例对应的点位（唯一标识
            String key = source.getLabel();
            // 获取生成的module(主要用于获取moduleId
            Map<Long, TStaticPropertiesModule> moduleMap = modules.get(source.getModuleId());
            moduleMap.forEach((parentId, module) -> {
                List<StaticPropertiesInstanceVO> values = templateMapping.getOrDefault(parentId, Collections.emptyList());
                List<Long> ids = values.stream().filter(i -> Objects.equals(i.getLabel(), key)).map(StaticPropertiesInstanceVO::getId).collect(Collectors.toList());
                delIds.addAll(ids);
                StaticPropertiesInstanceVO target = new StaticPropertiesInstanceVO();
                list.add(MyBeanUtil.doCopy(source, target, new Setter<>(target::setId, null), new Setter<>(target::setModuleId, module.getId())));
            });
        }
        staticPropertiesInstanceService.saveOrUpdateBatch(list);
        if (delIds.isEmpty()) {
            return;
        }
        staticPropertiesInstanceService.removeByIds(delIds);
    }

    private Map<Long, Map<Long, TStaticPropertiesModule>> getModules(Set<Long> moduleIds, Set<Long> parentIds) {
        Map<Long, Map<Long, TStaticPropertiesModule>> map = Maps.newHashMap();
        List<TStaticPropertiesModule> list = Lists.newArrayList();
        for (Long moduleId : moduleIds) {
            TStaticPropertiesModule module = staticPropertiesModuleService.getById(moduleId);
            module.setId(null);
            Map<Long, TStaticPropertiesModule> map1 = Maps.newHashMap();
            for (Long parentId : parentIds) {
                TStaticPropertiesModule module1 = new TStaticPropertiesModule();
                BeanUtils.copyProperties(module, module1);
                module1.setName(module.getName() + StringPool.UNDERSCORE + System.currentTimeMillis());
                module1.setTemplateId(parentId);
                map1.put(parentId, module1);
                list.add(module1);
            }
            map.put(moduleId, map1);
        }
        staticPropertiesModuleService.saveBatch(list);
        return map;
    }

}
